package com.gewei.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.gewei.constant.RedisConstant;
import com.gewei.dao.SetmealDao;
import com.gewei.entity.PageResult;
import com.gewei.pojo.Setmeal;
import com.gewei.service.SetmealService;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import redis.clients.jedis.JedisPool;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 预约管理-体检套餐管理服务
 *  加了 @Transactional 注解后，必须明确 interfaceClass
 *
 * @author gewei
 */
@Service(interfaceClass = SetmealService.class)
@Transactional(rollbackFor = Exception.class)
public class SetmealServiceImpl implements SetmealService {

    @Autowired
    private SetmealDao setmealDao;

    @Autowired
    private JedisPool jedisPool;

    @Autowired
    private FreeMarkerConfigurer freeMarkerConfigurer;

    /**
     * 从属性文件中读取要生成的 html 对应的目录
     */
    @Value("${out_put_path}")
    private String outPutPath;

    /**
     * 新增体检套餐，同时需要关联体检套餐和检查组多对多关系，生成静态页面
     *
     * @param setmeal
     * @param checkgroupIds
     */
    @Override
    public void add(Setmeal setmeal, Integer[] checkgroupIds) {
        setmealDao.add(setmeal);
        Integer setmealId = setmeal.getId();
        this.setSetmealAndCheckGroup(setmealId, checkgroupIds);
        //  将图片名称保存到 Redis 集合中
        jedisPool.getResource().sadd(RedisConstant.SETMEAL_PIC_DB_RESOURCES, setmeal.getImg());
        //  当添加套餐后需要重新生成静态页面（套餐列表页面、套餐详情页面）
        generateMobileStaticHtml();
    }

    /**
     * 设置体检套餐和检查组多对关系，操作 t_setmeal_checkgroup
     *
     * @param setmealId
     * @param checkgroupIds
     */
    private void setSetmealAndCheckGroup(Integer setmealId, Integer[] checkgroupIds) {
        if (checkgroupIds != null && checkgroupIds.length > 0) {
            for (Integer checkgroupId : checkgroupIds) {
                Map<String, Integer> map = new HashMap<>(16);
                map.put("setmeal_id", setmealId);
                map.put("checkgroup_id", checkgroupId);
                setmealDao.setSetmealAndCheckGroup(map);
            }
        }
    }

    /**
     * 分页查询体检套餐
     *
     * @param currentPage
     * @param pageSize
     * @param queryString
     * @return
     */
    @Override
    public PageResult pageQuery(Integer currentPage, Integer pageSize, String queryString) {
        PageHelper.startPage(currentPage, pageSize);
        Page<Setmeal> page = setmealDao.selectByCondition(queryString);
        return new PageResult(page.getTotal(), page.getResult());

    }

    /**
     * 查询所有体检套餐
     *
     * @return
     */
    @Override
    public List<Setmeal> findAll() {
        return setmealDao.findAll();
    }

    /**
     * 查询体检套餐（套餐基本信息、套餐对应的检查组信息、检查组对应的检查项信息）
     *
     * @param id
     * @return
     */
    @Override
    public Setmeal findById(int id) {
        return setmealDao.findById(id);
    }

    /**
     * 查询体检套餐预约数据
     *
     * @return
     */
    @Override
    public List<Map<String, Object>> findSetMealCount() {
        return setmealDao.findSetMealCount();
    }

    /**
     * 根据体检套餐 id 查询关联的所有检查组 id
     *
     * @param id
     * @return
     */
    @Override
    public List<Integer> findCheckGroupIdsBySetMealId(Integer id) {
        return setmealDao.findCheckGroupIdsBySetmealId(id);
    }

    /**
     * 编辑体检套餐（同时需要重新关联检查组）
     *
     * @param setmeal
     * @param checkgroupIds
     */
    @Override
    public void edit(Setmeal setmeal, Integer[] checkgroupIds) {
        //  编辑体检套餐基本信息，操作体检套餐 t_setmeal 表
        setmealDao.edit(setmeal);
        //  删除体检套餐关联的检查组，操作中间关系表 t_setmeal_checkgroup 表
        setmealDao.deleteAssociation(setmeal.getId());
        //  重新建立体检套餐和检查组的关联关系
        this.setSetmealAndCheckGroup(setmeal.getId(), checkgroupIds);

    }

    /**
     * 删除体检套餐
     *
     * @param id
     * @throws RuntimeException
     */
    @Override
    public void deleteById(Integer id) throws RuntimeException {
        //  删除体检套餐关联的检查组，操作中间关系表 t_setmeal_checkgroup 表
        setmealDao.deleteAssociation(id);
        //
        setmealDao.deleteById(id);
    }

    /**
     * 生成当前方法所需的静态页面
     */
    public void generateMobileStaticHtml() {
        //  在生成静态页面之前需要查询数据
        List<Setmeal> list = setmealDao.findAll();
        //  需要生成套餐列表静态页面
        generateMobileSetmealListHtml(list);
        //  需要生成套餐详情静态页面
        generateMobileSetmealDetailHtml(list);
    }

    /**
     * 生成套餐列表静态页面
     *
     * @param list
     */
    public void generateMobileSetmealListHtml(List<Setmeal> list) {
        Map map = new HashMap(16);
        map.put("setmealList", list);
        generateHtml("mobile_setmeal.ftl", "m_setmeal.html", map);
    }

    /**
     * 生成套餐详情静态页面（可能有多个）
     *
     * @param list
     */
    public void generateMobileSetmealDetailHtml(List<Setmeal> list) {
        for (Setmeal setmeal : list) {
            Map map = new HashMap(16);
            map.put("setmeal", setmealDao.findById(setmeal.getId()));
            generateHtml("mobile_setmeal_detail.ftl", "setmeal_detail_" + setmeal.getId() + ".html", map);
        }
    }

    /**
     * 通用的方法，用于生成静态页面
     *
     * @param templateName
     * @param htmlPageName
     * @param map
     */
    public void generateHtml(String templateName, String htmlPageName, Map map) {
        //  模板（获得 FreeMarker 配置对象）
        Configuration configuration = freeMarkerConfigurer.getConfiguration();
        Writer out = null;
        try {
            Template template = configuration.getTemplate(templateName);
            //  构造输出流
            out = new FileWriter(new File(outPutPath + "/" + htmlPageName));
            //  输出文件
            template.process(map, out);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TemplateException e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //  静态文件名
        //  模板所需要的数据
    }
}